package com.punai.dataanalysis.srlib.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.punai.common.exception.ServiceException;
import com.punai.common.exception.base.BaseException;
import com.punai.common.utils.NumberUtil;
import com.punai.common.utils.PageUtils;
import com.punai.common.utils.poi.ExcelUtil;
import com.punai.config.domain.ConfigMaterialCategory;
import com.punai.config.domain.ConfigMaterialInfo;
import com.punai.config.domain.vo.ConfigMaterialCategoryVo;
import com.punai.config.mapper.ConfigMaterialCategoryMapper;
import com.punai.config.mapper.ConfigMaterialInfoMapper;
import com.punai.config.service.ConfigMaterialPLCService;
import com.punai.dataanalysis.srlib.domain.AnalysisGovernmentPriceInfo;
import com.punai.dataanalysis.srlib.domain.AnalysisGovernmentPriceRecord;
import com.punai.dataanalysis.srlib.mapper.AnalysisGovernmentPriceInfoMapper;
import com.punai.dataanalysis.srlib.mapper.AnalysisGovernmentPriceRecordMapper;
import com.punai.dataanalysis.srlib.service.GovernmentPriceService;
import com.punai.dataanalysis.srlib.vo.GovernmentPriceVo;
import org.apache.commons.collections4.ListValuedMap;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class GovernmentPriceServiceImpl implements GovernmentPriceService {

    @Autowired
    private AnalysisGovernmentPriceRecordMapper governmentPriceRecordMapper;
    @Autowired
    private AnalysisGovernmentPriceInfoMapper governmentPriceInfoMapper;
    @Autowired
    private ConfigMaterialCategoryMapper materialCategoryMapper;
    @Autowired
    private ConfigMaterialInfoMapper materialInfoMapper;
    @Autowired
    private ConfigMaterialPLCService configMaterialPLCService;


    @Override
    public List<GovernmentPriceVo> getMainTableList(GovernmentPriceVo vo) {
        String type = vo.getType();
        String categoryId = vo.getCategoryId();
        List<ConfigMaterialCategoryVo> allCategory = configMaterialPLCService.getAllCategory(categoryId, type);
        List<ConfigMaterialInfo> materials = materialInfoMapper.selectList(
                Wrappers.<ConfigMaterialInfo>lambdaQuery()
                        .in(ConfigMaterialInfo::getCategoryId, allCategory.stream()
                                .map(ConfigMaterialCategoryVo::getId)
                                .collect(Collectors.toSet()))
                        .eq(ConfigMaterialInfo::getDataStatus,"0")
                        .eq(StrUtil.isNotEmpty(vo.getCode()), ConfigMaterialInfo::getCode,vo.getCode())
                        .eq(StrUtil.isNotEmpty(vo.getName()), ConfigMaterialInfo::getName,vo.getName())
                        .eq(StrUtil.isNotEmpty(vo.getSpec()), ConfigMaterialInfo::getSpec,vo.getSpec())
        );
        PageUtils.startPage();
        if(materials.size()==0) return Collections.emptyList();
        List<GovernmentPriceVo> list = governmentPriceInfoMapper.selectListByMaterialIdsOfGroup(
                materials.stream()
                .map(ConfigMaterialInfo::getId)
                .collect(Collectors.toList())
        );
        return list;
    }

    @Override
    public List<GovernmentPriceVo.ExportMianTable> downloadGovernmentPL(GovernmentPriceVo vo) {
        String type = vo.getType();
        String categoryId = vo.getCategoryId();
        List<ConfigMaterialCategoryVo> allCategory = configMaterialPLCService.getAllCategory(categoryId, type);
        List<ConfigMaterialInfo> materials = materialInfoMapper.selectList(
                Wrappers.<ConfigMaterialInfo>lambdaQuery()
                        .in(ConfigMaterialInfo::getCategoryId, allCategory.stream()
                                .map(ConfigMaterialCategoryVo::getId)
                                .collect(Collectors.toSet()))
                        .eq(StrUtil.isNotEmpty(vo.getCode()), ConfigMaterialInfo::getCode, vo.getCode())
                        .eq(StrUtil.isNotEmpty(vo.getName()), ConfigMaterialInfo::getName, vo.getName())
                        .eq(StrUtil.isNotEmpty(vo.getSpec()), ConfigMaterialInfo::getSpec, vo.getSpec())
        );
        if (materials.size() == 0) return Collections.emptyList();
        List<GovernmentPriceVo.ExportMianTable> list = governmentPriceInfoMapper.selectListByMaterialIdsOfGroup(
                materials.stream()
                        .map(ConfigMaterialInfo::getId)
                        .collect(Collectors.toList())
        ).stream().map(v->{
            GovernmentPriceVo.ExportMianTable re = new GovernmentPriceVo.ExportMianTable();
            BeanUtil.copyProperties(v, re);
            return re;
        }).collect(Collectors.toList());
        return list;
    }

    @Override
    public List<GovernmentPriceVo> getTableListByMaterialId(GovernmentPriceVo vo) {
        return governmentPriceInfoMapper.selectListByMaterialId(vo.getMaterialId());
    }

    @Override
    public List<String> getTjtMapByMaterialId(GovernmentPriceVo vo) {
        return governmentPriceInfoMapper.getTjtMapByMaterialId(vo.getMaterialId());
    }

    @Override
    public Boolean saveRecord(GovernmentPriceVo vo) {
        AnalysisGovernmentPriceRecord one = null;
        if(StrUtil.isNotEmpty(vo.getId())){
            one = governmentPriceRecordMapper.selectById(vo.getId());
        }
        AnalysisGovernmentPriceRecord conversion = AnalysisGovernmentPriceRecord.conversion(vo, one, 1);
        if(StrUtil.isNotEmpty(conversion.getId()))
            governmentPriceRecordMapper.updateById(conversion);
        else
            governmentPriceRecordMapper.insert(conversion);
        return true;
    }

    @Override
    public List<AnalysisGovernmentPriceRecord> getRecordList(GovernmentPriceVo vo) {
        PageUtils.startPage();
        Map<String, List<ConfigMaterialCategoryVo>> map_type = materialCategoryMapper.selectAllAddress(type).stream().collect(Collectors.groupingBy(ConfigMaterialCategory::getId));
        return governmentPriceRecordMapper.selectList(Wrappers.<AnalysisGovernmentPriceRecord>lambdaQuery()
                .eq(AnalysisGovernmentPriceRecord::getDataStatus, "0")
        ).stream().peek(v->{
            List<ConfigMaterialCategoryVo> categoryVos = map_type.get(v.getUploadAddress());
            if(categoryVos.size()>0) v.setUploadAddressName(categoryVos.get(0).getAddress());
        }).collect(Collectors.toList());
    }

    @Override
    public Boolean deleteRecord(GovernmentPriceVo vo) {
        AnalysisGovernmentPriceRecord record = governmentPriceRecordMapper.selectById(vo.getId());
        record.setDataStatus("1");
        governmentPriceRecordMapper.updateById(record);
        governmentPriceInfoMapper.delete(Wrappers.<AnalysisGovernmentPriceInfo>lambdaQuery()
                .eq(AnalysisGovernmentPriceInfo::getRecordId, record.getId()));
        return true;
    }

    @Override
    public List<GovernmentPriceVo> getInfoList(GovernmentPriceVo vo) {
        PageUtils.startPage();
        return governmentPriceInfoMapper.selectAllByRecordId(vo.getRecordId());
    }

    @Override
    public String uploadInfo(String recordId, MultipartFile uploadFile) {
        ExcelUtil<GovernmentPriceVo> util = new ExcelUtil<>(GovernmentPriceVo.class);
        StringBuilder sb = new StringBuilder();
        try {
            List<GovernmentPriceVo> infos = util.importExcel(uploadFile.getInputStream());
            Set<String> codes = new HashSet<>();
            ListValuedMap<String, GovernmentPriceVo> valuedHashMap = new ArrayListValuedHashMap<>();
            for (GovernmentPriceVo info : infos) {
                String code = info.getCode();
                String brand = StrUtil.emptyToDefault(info.getBrand(),"暂无");
                codes.add(code);
                info.setBrand(brand);
                valuedHashMap.put(code+"==="+brand,info);
            }
            Map<String, List<ConfigMaterialInfo>> codeMap = materialInfoMapper.selectList(
                    Wrappers.<ConfigMaterialInfo>lambdaQuery()
                            .in(ConfigMaterialInfo::getCode, codes))
                    .stream()
                    .collect(Collectors.groupingBy(ConfigMaterialInfo::getCode));
            Integer order = 0;
            for (String key : valuedHashMap.keySet()) {
                String[] split = key.split("===");
                String code = split[0];
                String brand = split[1];
                GovernmentPriceVo infoVo = valuedHashMap.get(key).get(0);
                List<ConfigMaterialInfo> list = codeMap.get(code);
                if(list==null) {
                    sb.append("编码为：").append(code).append("的材料不存在").append("\r\n");
                    continue;
                }
                if(CollUtil.isNotEmpty(list)){
                    ConfigMaterialInfo material = list.get(0);
                    AnalysisGovernmentPriceInfo one = ObjectUtil.defaultIfNull(governmentPriceInfoMapper.selectOne(Wrappers.<AnalysisGovernmentPriceInfo>lambdaQuery()
                            .eq(AnalysisGovernmentPriceInfo::getRecordId, recordId)
                            .eq(AnalysisGovernmentPriceInfo::getMaterialId, material.getId())
                            .eq(AnalysisGovernmentPriceInfo::getBrand, brand)
                    ), new AnalysisGovernmentPriceInfo());
                    one.setMaterialId(material.getId());
                    one.setRecordId(recordId);
                    one.setBrand(infoVo.getBrand());
                    Map<String, Object> calcPrice = this.calcPrice(infoVo.getTax(), infoVo.getPriceWithNotTax(), infoVo.getPriceWithTax());
                    if (calcPrice.containsKey("error")) {
                        sb.append("编码为：").append(code).append("的材料,").append(calcPrice.get("error")).append("\r\n");;
                        continue;
                    }
                    one.setPriceWithNotTax(NumberUtil.getValue(calcPrice.get("priceWithNotTax")));
                    one.setPriceWithTax(NumberUtil.getValue(calcPrice.get("priceWithTax")));
                    one.setTax(NumberUtil.getValue(calcPrice.get("tax")));
                    if (StrUtil.isNotBlank(one.getId())) {
                        governmentPriceInfoMapper.updateById(one);
                    } else  {
                        one.setOrderNum(order);
                        order++;
                        governmentPriceInfoMapper.insert(one);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException(e.getMessage());
        }
        return sb.toString();
    }
    @Override
    public List<GovernmentPriceVo> downloadTemplete(String recordId) {
        //根据记录查地区id
        AnalysisGovernmentPriceRecord record = governmentPriceRecordMapper.selectById(recordId);
        //根据工具地区id收集分类id
        List<ConfigMaterialCategoryVo> allCategory = configMaterialPLCService.getAllCategory(record.getUploadAddress(), type);
        //根据分类id获取材料
        List<ConfigMaterialInfo> all = materialInfoMapper.selectList(Wrappers.<ConfigMaterialInfo>lambdaQuery()
                .in(ConfigMaterialInfo::getCategoryId, allCategory.stream().map(ConfigMaterialCategoryVo::getId).collect(Collectors.toSet()))
                .eq(ConfigMaterialInfo::getDataStatus, "0")
        );
        return all.stream().map(v -> {
            GovernmentPriceVo re = new GovernmentPriceVo();
            BeanUtil.copyProperties(v, re);
            return re;
        }).collect(Collectors.toList());
    }

    private Map<String,Object> calcPrice(BigDecimal sl, BigDecimal price, BigDecimal taxPrice){
        if((sl == null && price == null) || (sl == null && taxPrice == null)
                || price == null && taxPrice == null){
            return new HashMap<String,Object>(){{
                put("error","含税价，除税价，税率至少有两个不为空!");
            }};
        }

        HashMap<String,Object> hashMap = new HashMap<>();

        if(price == null){
            BigDecimal taxPriceDecimal = taxPrice;
            if(sl.compareTo(BigDecimal.ONE) > 0 || sl.compareTo(BigDecimal.ONE)==0){
                sl = sl.divide(new BigDecimal(100),2,BigDecimal.ROUND_HALF_UP);
            }
            BigDecimal slDecimal = sl;
            price = taxPriceDecimal.divide(new BigDecimal(1).add(slDecimal), 4, RoundingMode.HALF_DOWN);
        }
        if(taxPrice == null){
            if(sl.compareTo(BigDecimal.ONE) > 0 || sl.compareTo(BigDecimal.ONE)==0){
                sl=sl.divide(new BigDecimal(100),2, RoundingMode.HALF_UP);
            }
            BigDecimal slDecimal = sl;
            taxPrice = price.multiply(new BigDecimal(1).add(slDecimal)).setScale(4, RoundingMode.HALF_UP);
        }

        if(sl == null){
           sl = taxPrice.divide(price, RoundingMode.HALF_UP).subtract(new BigDecimal(1)).setScale(4, RoundingMode.HALF_UP);
        }
        // 判定是否不合理
        BigDecimal tp = NumberUtil.getValue(taxPrice);
        BigDecimal p = NumberUtil.getValue(price);
        if (NumberUtil.compareTo(p,tp) == 1) {
            // 不含税 > 含税
            throw new ServiceException("存在不含税大于含税!");
        }
        hashMap.put("tax", sl);
        hashMap.put("priceWithTax", taxPrice);
        hashMap.put("priceWithNotTax", price);
        return hashMap;
    }
}
